package org.urey.fmp.consumer.processor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.urey.fmp.commom.annotation.CustomRequestBody;

import feign.MethodMetadata;

@Component
public class CustomRequestBodyParameterProcessor implements AnnotatedParameterProcessor {

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private CustomJsonExpander customJsonExpander;

	private static final Class<CustomRequestBody> ANNOTATION = CustomRequestBody.class;

	@Override
	public Class<? extends Annotation> getAnnotationType() {
		return ANNOTATION;
	}

	@Override
	public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
		int parameterIndex = context.getParameterIndex();
		Class<?> parameterType = method.getParameterTypes()[parameterIndex];
		MethodMetadata data = context.getMethodMetadata();

		if (Map.class.isAssignableFrom(parameterType)) {
			Assert.state(data.queryMapIndex() == null, "Query map can only be present once.");
			data.queryMapIndex(parameterIndex);

			return true;
		}

		CustomRequestBody requestParam = ANNOTATION.cast(annotation);
		String name = requestParam.value();
		Assert.state(StringUtils.isNotBlank(name), "CustomRequestParam.value() was empty on parameter " + parameterIndex);
		context.setParameterName(name);
		data.formParams().add(name);

		List<String> formParams = data.formParams();
		StringBuffer stringBuffer = new StringBuffer("%7B");
		for (int i = 0; i < formParams.size(); i++) {
			boolean isList = false;

			Set<String> types = getAllInterfaces(method.getParameterTypes()[i]);
			if (types.contains("java.util.Collection")) {
				isList = true;
			}

			String param = formParams.get(i);
			stringBuffer.append("\"" + param + "\"").append(":");
			if (isList) {
				stringBuffer.append("[");
			}
			stringBuffer.append("{").append(param).append("}");
			if (isList) {
				stringBuffer.append("]");
			}
			if (i < formParams.size() - 1) {
				stringBuffer.append(",");
			}
		}
		stringBuffer.append("%7D");

		logger.debug("feign template:{}:{}", data.configKey(), stringBuffer);

		data.template().bodyTemplate(stringBuffer.toString());
		data.template().header("content-type", "application/json");

		data.indexToExpander().put(context.getParameterIndex(), customJsonExpander);
		return true;
	}

	/**
	 * 获取该对象的类,类的所有实现接口,类的父类的名称
	 * 
	 * @param object
	 * @return
	 */
	private static Set<String> getAllInterfaces(Class<?> clazz) {
		Set<String> types = new HashSet<String>();
		Stack<Class<?>> stack = new Stack<Class<?>>();
		stack.push(clazz);
		while (!stack.empty()) {
			Class<?> c = stack.pop();
			types.add(c.getName());
			Class<?> superClass = c.getSuperclass();
			if (superClass != null) {
				stack.push(superClass);
			}
			Class<?>[] cs = c.getInterfaces();
			for (Class<?> superClazzs : cs) {
				stack.push(superClazzs);
			}
		}
		return types;
	}

}
